/*************************************************
Author: will
Date: 2013/03/23
Description:
Notes:
*************************************************/

#ifndef __COssMgr_cpp__
#define __COssMgr_cpp__

#include "../mainctrl.h"
#include "COssMgr.h"
#include "../cmdinner/CCmdOss.h"
#include "commmsg.h"
#include "CTSizeString.h"
#include "MsgOfficeGM.pb.h"

//OSS数据重置时间 0 点
#define  OSS_DATA_RESET_TIME  0

void COssMgr::TimeTick(int iNowTime)
{
    if (0 == _iLastUpdateTime)
    {
        _iLastUpdateTime = iNowTime /  OSS_ZONE_UPDATE_INTERVAL * OSS_ZONE_UPDATE_INTERVAL;   //初始化更新时间
        _iLastNewDayCheck = CTTimeUtils::GetDayBeginSec(iNowTime);
    }

    //未到更新时间
    if ((iNowTime - _iLastUpdateTime) >= OSS_ZONE_UPDATE_INTERVAL)
    {
        UpdateZoneData(_iLastUpdateTime);

        //确保15分钟更新一次
        _iLastUpdateTime = iNowTime /  OSS_ZONE_UPDATE_INTERVAL * OSS_ZONE_UPDATE_INTERVAL;
    }

    //跨天统计
    if (!CTTimeUtils::IsSameDay(iNowTime, _iLastNewDayCheck, OSS_DATA_RESET_TIME))
    {
        _iLastNewDayCheck = CTTimeUtils::GetDayBeginSec(iNowTime);

        CTArray<unsigned int, MAX_PLAYER_ONLINE> astGIDArray;
        CMainCtrl::m_pstMain->m_stPlayerOnline.GetAllOnlineUser(astGIDArray);
        for (int i = 0; i < astGIDArray.Size(); ++i)
        {
            TriggerNewday(astGIDArray[i]);
        }
    }
}

void COssMgr::UpdateZoneData(int iUpdateTime)
{
    _stOssZoneData._iUpdateTime = iUpdateTime;
    _stOssZoneData._uiZoneID = CONF->ZoneID;

    //在线数据
    _stOssZoneData._iNowOnline = CMainCtrl::m_pstMain->m_stPlayerOnline.GetOnlineCount();

    //注册用户数
    _stOssZoneData._iQuarterRegister = _iQuarterRegister;
    _stOssZoneData._uiQuarterIncome = _uiQuarterIncome;

    _iQuarterRegister = 0;
    _uiQuarterIncome = 0;

    CVarObjectKey stKey;
    stKey.m_chDataType = DT_OSS_ZONE_DATA;
    stKey.m_u64ID = CT_UINT64_MAKE(_stOssZoneData._uiZoneID, _stOssZoneData._iUpdateTime);
    CMainCtrl::m_pstMain->UpdateData(stKey, _stOssZoneData, VOP_UPDATE);
}

void COssMgr::TriggerRegister(unsigned int uiGID)
{
    COssPlayerTriggerData stData;
    stData._uiGID = uiGID;
    stData._uiTriggerType = OSS_TRIGGER_REGISTER;
    stData._iData1 = CMainCtrl::m_pstMain->m_iNow;

    //每15分钟注册用户数
    _iQuarterRegister++;

    TriggerPlayer(stData);
}

void COssMgr::TriggerAct(unsigned int uiGID)
{
    COssPlayerTriggerData stData;
    stData._uiGID = uiGID;
    stData._uiTriggerType = OSS_TRIGGER_ACT;
    stData._iData1 = CMainCtrl::m_pstMain->m_iNow;

    TriggerPlayer(stData);
}

void COssMgr::TriggerFirstPay(unsigned int uiGID, int iFee)
{
    if (iFee <= 0)
    {
        CT_ERROR(("%d,%d", uiGID, iFee));
    }

    COssPlayerTriggerData stData;
    stData._uiGID = uiGID;
    stData._uiTriggerType = OSS_TRIGGER_PAY;
    stData._iData1 = CMainCtrl::m_pstMain->m_iNow;
    stData._iData2 = iFee;

    TriggerPlayer(stData);
}

void COssMgr::TriggerLogin(unsigned int uiGID, int iNowTime)
{
    COssPlayerTriggerData stData;
    stData._uiGID = uiGID;
    stData._uiTriggerType = OSS_TRIGGER_LOGIN;
    stData._iData1 = iNowTime;

    TriggerPlayer(stData);
}

void COssMgr::TriggerCreate(CPlayerBaseInfo& stPlayerBaseInfo)
{
    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return;
    }

    CT_BILL(("%d|%d|%u|%s", CMainCtrl::m_pstMain->m_iNow,
        OSS_MODULE_CREATE_ROLE, stPlayerBaseInfo._uiGID,
        stPlayerBaseInfo._sRoleName()));
}

void COssMgr::TriggerLogin(CPlayerBaseInfo& stPlayerBaseInfo,
        CPlayerDetailInfo& stPlayerDetailInfo)
{
    if (stPlayerBaseInfo._ucIsInited != 1)
    {
        return;
    }

    CT_BILL(("%d|%d|%u|%s|%u", CMainCtrl::m_pstMain->m_iNow,
        OSS_MODULE_ROLE_LOGIN, stPlayerBaseInfo._uiGID,
        stPlayerBaseInfo._sRoleName(),
        stPlayerDetailInfo._stUserClan._uiClanId));
}

void COssMgr::TriggerLogout(unsigned int uiGID, int iNowTime)
{
    COssPlayerTriggerData stData;
    stData._uiGID = uiGID;
    stData._uiTriggerType = OSS_TRIGGER_LOGOUT;
    stData._iData1 = iNowTime;

    TriggerPlayer(stData);
}

void COssMgr::TriggerNewday(unsigned int uiGID)
{
    COssPlayerTriggerData stData;
    stData._uiGID = uiGID;
    stData._uiTriggerType = OSS_TRIGGER_NEWDAY;
    stData._iData1 = CMainCtrl::m_pstMain->m_iNow;

    TriggerPlayer(stData);
}

void COssMgr::TriggerMoney(unsigned int uiGID, unsigned char ucOpt, unsigned short usModuleId, int iAmount)
{
    static unsigned int uiMoneySeqNo = 0;   //OSS入库的流水号
    if (0 == iAmount)
    {
        return;
    }

    CPlayerOssMoney stPlayerMoney;
    stPlayerMoney._uiGID = uiGID;
    stPlayerMoney._iUpdateTime = CMainCtrl::m_pstMain->m_iNow;
    stPlayerMoney._ucOpt = ucOpt;
    stPlayerMoney._usModule = usModuleId;
    stPlayerMoney._iAmount = iAmount;

    if (OSS_MONEY_ADD_GOLD == ucOpt && (OSS_MODULE_VIP == usModuleId || OSS_MODULE_32WAN_ADD_GOLD == usModuleId))
    {
        _uiQuarterIncome += iAmount;
    }

    CT_ASSERT((usModuleId));
    CT_BILL(("%d|%d|%u|%d|%d", CMainCtrl::m_pstMain->m_iNow, ucOpt, uiGID, usModuleId, iAmount));

    CVarObjectKey stKey;
    stKey.m_chDataType = DT_OSS_PLAYER_MONEY;
    stKey.m_u64ID = CT_UINT64_MAKE(uiMoneySeqNo, uiGID);
    CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerMoney, VOP_UPDATE);
    uiMoneySeqNo += 1;
}

void COssMgr::TriggerQQPay(unsigned int uiGID, int iQcent, int iGameCoin, int iCertiCoin, const char * pcBillno)
{
    CT_BILL(("%d|%d|%u|%d|%d|%d|%s", CMainCtrl::m_pstMain->m_iNow, OSS_MODULE_QQ_PAY, uiGID, iQcent, iGameCoin, iCertiCoin, pcBillno));
}

void COssMgr::TriggerExit (unsigned int uiGID, int iNowTime)
{
    COssPlayerTriggerData stData;
    stData._uiGID = uiGID;
    stData._uiTriggerType = OSS_TRIGGER_EXIT;
    stData._iData1 = iNowTime;

    TriggerPlayer(stData);

}

void COssMgr::TriggerPlayer(COssPlayerTriggerData& stData)
{
    int iIndex = CMainCtrl::m_pstMain->m_stPlayerSnsDetailInfoHash.HashFind(stData._uiGID);
    if (iIndex < 0)
    {
        PreparePlayerOssInfo(stData);
        return;
    }

    int iNowTime = stData._iData1;
    CPlayerSnsDetailInfo& stPlayerSnsDetailInfo = CMainCtrl::m_pstMain->m_stPlayerSnsDetailInfoHash[iIndex];
    CPlayerOssInfo& stPlayerOssInfo = stPlayerSnsDetailInfo._stMyInfo._stPlayerOssInfo;

    bool bNeedUpdateOss = false;
    bool bNeedUpdateSnsDetail = false;

    switch (stData._uiTriggerType)
    {
    case OSS_TRIGGER_REGISTER:
        {
            stPlayerOssInfo._iRegTime = stData._iData1;
            stPlayerOssInfo._usLevel = stPlayerSnsDetailInfo._stCommInfo._usLevel;

            bNeedUpdateOss = true;
            bNeedUpdateSnsDetail = true;
        }
        break;
    case OSS_TRIGGER_NEWDAY:    //跨天
        {
            TriggerLogout(stData._uiGID, CTTimeUtils::GetDayBeginSec(iNowTime) - 1);
            TriggerLogin(stData._uiGID, CTTimeUtils::GetDayBeginSec(iNowTime));
        }
        break;
    case OSS_TRIGGER_ACT: //活跃
        {
            stPlayerOssInfo._iLastActTime = iNowTime;
            stPlayerOssInfo._usLevel = stPlayerSnsDetailInfo._stCommInfo._usLevel;

            bNeedUpdateOss = true;
            bNeedUpdateSnsDetail = true;
        }
        break;
    case OSS_TRIGGER_PAY:
        {
            if (stPlayerOssInfo._ucHasPaied == 0)
            {
                stPlayerOssInfo._ucHasPaied = 1;
                stPlayerOssInfo._iFirstPayTime = stData._iData1;
                stPlayerOssInfo._iFirstPayFee = stData._iData2;

                bNeedUpdateOss = true;
                bNeedUpdateSnsDetail = true;
            }
        }
        break;
    case OSS_TRIGGER_LOGIN:
        {
            if (!CTTimeUtils::IsSameDay(stPlayerOssInfo._iLastLoginTime, iNowTime, OSS_DATA_RESET_TIME))
            {
                stPlayerOssInfo._iTodayLoginSec = 0;
            }

            stPlayerOssInfo._iLastLoginTime = iNowTime;
            bNeedUpdateSnsDetail = true;
            bNeedUpdateOss = true;
        }
        break;    
    
    case OSS_TRIGGER_EXIT:
        {
            if (iNowTime >= stPlayerOssInfo._iLastLoginTime)
            {
                stPlayerOssInfo._iTodayLoginSec += (iNowTime - stPlayerOssInfo._iLastLoginTime);
                stPlayerOssInfo._iLastLoginTime = iNowTime;  //更新登陆时间, 防止重复计算在线时间
                bNeedUpdateSnsDetail = true;
                bNeedUpdateOss = true;
            }
            else
            {
                CT_ERROR(("%d, %d, %d", stData._uiGID, iNowTime, stPlayerOssInfo._iLastLoginTime));
            }        
        }
        break;
    case OSS_TRIGGER_LOGOUT:    
        {
            if (iNowTime >= stPlayerOssInfo._iLastLoginTime)
            {
                stPlayerOssInfo._iTodayLoginSec += (iNowTime - stPlayerOssInfo._iLastLoginTime);
                bNeedUpdateSnsDetail = true;
                bNeedUpdateOss = true;
            }
            else
            {
                CT_ERROR(("%d, %d, %d", stData._uiGID, iNowTime, stPlayerOssInfo._iLastLoginTime));
            }
        }
        break;

    default:
        return;
    }

    //初始化结构
    CPlayerOssData stPlayerOssData;
    stPlayerOssData._iUpdateTime = iNowTime;
    stPlayerOssData._uiGID = stData._uiGID;
    stPlayerOssData._ucHasPaied = stPlayerOssInfo._ucHasPaied;
    stPlayerOssData._usNowLevel = stPlayerOssInfo._usLevel;
    stPlayerOssData._iFirstPayTime = stPlayerOssInfo._iFirstPayTime;
    stPlayerOssData._iFirstPayFee = stPlayerOssInfo._iFirstPayFee;
    stPlayerOssData._iRegTime = stPlayerOssInfo._iRegTime;
    stPlayerOssData._iLoginTime = stPlayerOssInfo._iLastLoginTime;
    stPlayerOssData._iActTime = stPlayerOssInfo._iLastActTime;
    stPlayerOssData._iTodayLoginSec = stPlayerOssInfo._iTodayLoginSec;

    if (bNeedUpdateOss)
    {
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_OSS_PLAYER_DATA;
        stKey.m_u64ID = CT_UINT64_MAKE(stPlayerOssData._uiGID, CTTimeUtils::GetDayBeginSec(iNowTime)); //可能同一时间下发很多同一个GID的数据，但是一个数据同一天只有一个
        CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerOssData, VOP_UPDATE);
    }

    if (bNeedUpdateSnsDetail)
    {
        CVarObjectKey stKey;
        stKey.m_chDataType = DT_PLAYER_SNS_DETAIL_INFO;
        stKey.m_u64ID = stPlayerSnsDetailInfo._uiGID;
        CMainCtrl::m_pstMain->UpdateData(stKey, stPlayerSnsDetailInfo, VOP_UPDATE);
    }
}

void COssMgr::PreparePlayerOssInfo(COssPlayerTriggerData& stData)
{
    CCmdOss* pstCmd = (CCmdOss*)CT_CMDFACTORY->CreateCmd(ID_MAINDB_OSS);
    if (!pstCmd)
    {
        CT_WARNING(("create cmd error"));
        return ;
    }

    pstCmd->pstMainCtrl = CMainCtrl::m_pstMain;
    pstCmd->stOssPlayerTriggerData = stData;
    pstCmd->Do(NULL);
}

void COssMgr::TriggerGMSendGift(unsigned int uiGID, MsgReqOfficeGM& stReq)
{
    if (stReq.datas_size() <= 0)
    {
        return;
    }

    CTSizeString<MAX_OSS_ITEM_STRING_LEN> szItemList;

    for (int i = 0; i < stReq.datas_size(); i+=2)
    {
        szItemList.Cat("|%u",(unsigned int)stReq.datas(i));
        if (i + 1 < stReq.datas_size())
        {
            szItemList.Cat("|%d",stReq.datas(i + 1));
        }
    }

    CT_BILL(("%d|%d|%u|%s", CMainCtrl::m_pstMain->m_iNow,
        OSS_MODULE_GM, uiGID, szItemList.Get()));
}

//物品的产出与消耗
void COssMgr::TriggerItem(unsigned int uiGID, int iOptType)
{
    if (_astConsume.Size() <= 0 && _astProduce.Size() <= 0)
    {
        return;
    }

    CTSizeString<MAX_OSS_ITEM_STRING_LEN> szCardList;

    if (_astProduce.Size() > 0)
    {
        szCardList.Set("");
        for (int i = 0; i < _astProduce.Size(); ++i)
        {
            szCardList.Cat("|%d",_astProduce[i]._ucItemType);//物品类型
            szCardList.Cat("|%d",_astProduce[i]._iItemCount);//物品数量
            szCardList.Cat("|%d",_astProduce[i]._usItemConfigID);//物品配置ID
            szCardList.Cat("|%u",(unsigned int)_astProduce[i]._iData1);//角色自增ID
        }

        CT_BILL(("%d|%d|%u|%d%s", CMainCtrl::m_pstMain->m_iNow,
            OSS_MODULE_ITEM_PRODUCE, uiGID, iOptType, szCardList.Get()));
    }

    if (_astConsume.Size() > 0)
    {
        szCardList.Set("");
        for (int i = 0; i < _astConsume.Size(); ++i)
        {
            szCardList.Cat("|%d",_astConsume[i]._ucItemType);//物品类型
            szCardList.Cat("|%d",_astConsume[i]._iItemCount);//物品数量
            szCardList.Cat("|%d",_astConsume[i]._usItemConfigID);//物品配置ID
            szCardList.Cat("|%u",(unsigned int)_astConsume[i]._iData1);//角色自增ID
        }

        CT_BILL(("%d|%d|%u|%d%s", CMainCtrl::m_pstMain->m_iNow,
            OSS_MODULE_ITEM_CONSUME, uiGID, iOptType, szCardList.Get()));
    }
}

#endif
